package com.yf.exam.modules.paper.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.yf.exam.core.api.ApiRest;
import com.yf.exam.core.api.controller.BaseController;
import com.yf.exam.core.api.dto.BaseIdReqDTO;
import com.yf.exam.core.api.dto.BaseIdRespDTO;
import com.yf.exam.core.api.dto.PagingReqDTO;
import com.yf.exam.core.utils.BeanMapper;
import com.yf.exam.core.utils.excel.ExportExcel;
import com.yf.exam.core.utils.pdf.PdfFileUtil;
import com.yf.exam.modules.exam.dto.ExamDTO;
import com.yf.exam.modules.exam.service.ExamService;
import com.yf.exam.modules.paper.dto.*;
import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO;
import com.yf.exam.modules.paper.dto.request.PaperAnswerDTO;
import com.yf.exam.modules.paper.dto.request.PaperCreateReqDTO;
import com.yf.exam.modules.paper.dto.request.PaperListReqDTO;
import com.yf.exam.modules.paper.dto.request.PaperQuQueryDTO;
import com.yf.exam.modules.paper.dto.response.ExamDetailRespDTO;
import com.yf.exam.modules.paper.dto.response.ExamResultRespDTO;
import com.yf.exam.modules.paper.dto.response.PaperListRespDTO;
import com.yf.exam.modules.paper.entity.ExamApply;
import com.yf.exam.modules.paper.entity.PaperQu;
import com.yf.exam.modules.paper.entity.PaperQuAnswer;
import com.yf.exam.modules.paper.service.ExamApplyService;
import com.yf.exam.modules.paper.service.PaperQuAnswerService;
import com.yf.exam.modules.paper.service.PaperQuService;
import com.yf.exam.modules.paper.service.PaperService;
import com.yf.exam.modules.qu.entity.Qu;
import com.yf.exam.modules.qu.entity.QuAnswer;
import com.yf.exam.modules.qu.service.QuAnswerService;
import com.yf.exam.modules.qu.service.QuService;
import com.yf.exam.modules.sys.depart.service.SysDepartService;
import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO;
import com.yf.exam.modules.sys.user.entity.SysUser;
import com.yf.exam.modules.sys.user.service.SysUserService;
import com.yf.exam.modules.user.UserUtils;
import com.yf.exam.modules.user.exam.entity.UserExam;
import com.yf.exam.modules.user.exam.service.UserExamService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 试卷控制器
 * </p>
 *
 * @author 聪明笨狗
 * @since 2020-05-25 16:33
 */
@Slf4j
@Api(tags = {"试卷"})
@RestController
@RequestMapping("/exam/api/paper/paper")
public class PaperController extends BaseController {
    @Value("${image-root}")
    private String imageRoot;
    @Value("${qr-root}")
    private String qrRoot;
    @Value("${exam-order-id}")
    private List<String> examOrderId;

    @Autowired
    private PaperService paperService;

    @Autowired
    private SysDepartService sysDepartService;
    @Autowired
    private ExamApplyService examApplyService;
    @Autowired
    private PdfFileUtil pdfFileUtil;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private UserExamService userExamService;
    @Autowired
    private ExamService examService;
    @Autowired
    private PaperQuService paperQuService;
    @Autowired
    private PaperQuAnswerService paperQuAnswerService;
    @Autowired
    private QuAnswerService quAnswerService;
    @Autowired
    private QuService quService;

    private static final int width = 300;
    private static final int height = 300;
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * 分页查找
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "分页查找")
    @RequestMapping(value = "/paging", method = {RequestMethod.POST})
    public ApiRest<IPage<PaperListRespDTO>> paging(@RequestBody PagingReqDTO<PaperListReqDTO> reqDTO) {
        //分页查询并转换
        IPage<PaperListRespDTO> page = paperService.paging(reqDTO);
        return super.success(page);
    }


    /**
     * 创建试卷
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "创建试卷")
    @RequestMapping(value = "/create-paper", method = {RequestMethod.POST})
    public ApiRest<BaseIdRespDTO> save(@RequestBody PaperCreateReqDTO reqDTO) {
        //复制参数
        String paperId = paperService.createPaper(UserUtils.getUserId(), reqDTO.getExamId());
        return super.success(new BaseIdRespDTO(paperId));
    }

    /**
     * 批量删除
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "试卷详情(包含所有题目、选项)")
    @RequestMapping(value = "/paper-detail", method = {RequestMethod.POST})
    public ApiRest<ExamDetailRespDTO> paperDetail(@RequestBody BaseIdReqDTO reqDTO) {
        ExamDetailRespDTO respDTO = paperService.paperDetail(reqDTO.getId());
        return super.success(respDTO);
    }

    /**
     * 批量删除
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "试题详情")
    @RequestMapping(value = "/qu-detail", method = {RequestMethod.POST})
    public ApiRest<PaperQuDetailDTO> quDetail(@RequestBody PaperQuQueryDTO reqDTO) {
        PaperQuDetailDTO respDTO = paperService.findQuDetail(reqDTO.getPaperId(), reqDTO.getQuId());
        return super.success(respDTO);
    }

    /**
     * 填充答案
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "填充答案")
    @RequestMapping(value = "/fill-answer", method = {RequestMethod.POST})
    public ApiRest<PaperQuDetailDTO> fillAnswer(@RequestBody PaperAnswerDTO reqDTO) {
        paperService.fillAnswer(reqDTO);
        return super.success();
    }


    /**
     * 交卷操作
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "交卷操作")
    @RequestMapping(value = "/hand-exam", method = {RequestMethod.POST})
    public ApiRest<PaperQuDetailDTO> handleExam(@RequestBody BaseIdReqDTO reqDTO) {
        SysUserLoginDTO user = getLoginUser();
        paperService.handExam(reqDTO.getId(), user);
        return super.success();
    }


    /**
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "试卷详情(包含题目)")
    @RequestMapping(value = "/paper-result", method = {RequestMethod.POST})
    public ApiRest<ExamResultRespDTO> paperResult(@RequestBody BaseIdReqDTO reqDTO) {
        ExamResultRespDTO respDTO = paperService.paperResult(reqDTO.getId());
        return super.success(respDTO);
    }


    /**
     * 检测用户有没有中断的考试
     *
     * @return
     */
    @ApiOperation(value = "检测进行中的考试")
    @RequestMapping(value = "/check-process", method = {RequestMethod.POST})
    public ApiRest<PaperDTO> checkProcess() {
        // 复制参数
        PaperDTO dto = paperService.checkProcess(UserUtils.getUserId());
        return super.success(dto);
    }

    /**
     * 申请考试
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "申请考试")
    @RequestMapping(value = "/applyExam", method = {RequestMethod.POST})
    public ApiRest<SysExamApply> applyExam(@RequestBody SysExamApply reqDTO) {
        SysUserLoginDTO user = getLoginUser();
        paperService.applyExam(reqDTO, user);
        return super.success();
    }

    /**
     * 修改考试申请
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "申请考试")
    @RequestMapping(value = "/updateApply", method = {RequestMethod.POST})
    public ApiRest<SysExamApply> updateApply(@RequestBody SysExamApply reqDTO) {
        paperService.updateApply(reqDTO);
        return super.success();
    }

    /**
     * 删除考试申请
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "删除考试申请")
    @RequestMapping(value = "/deleteApply", method = {RequestMethod.POST})
    public ApiRest<SysExamApply> deleteApply(@RequestBody SysExamApply reqDTO) {
        paperService.deleteApply(reqDTO);
        return super.success();
    }

    /**
     * 申请考试列表
     *
     * @param reqDTO
     * @return
     */
    @ApiOperation(value = "申请考试列表")
    @RequestMapping(value = "/applyExamList", method = {RequestMethod.POST})
    public ApiRest<IPage<SysExamApply>> applyExamList(@RequestBody PagingReqDTO<SysExamApply> reqDTO) {
        IPage<SysExamApply> page = paperService.applyExamList(reqDTO);
        return super.success(page.convert(index -> {
                    try {
                        final String content = qrRoot + "/#/qr-code/" + URLEncoder.encode(index.getUserName(), "UTF-8");
                        BufferedImage qrImage = generateQRCodeImage(content, 300, 300);
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        ImageIO.write(qrImage, "png", baos);
                        byte[] imageBytes = baos.toByteArray();
                        // 使用 Base64 编码
                        Base64.Encoder encoder = Base64.getEncoder();
                        index.setQrCodeBase64("data:image/png;base64," + encoder.encodeToString(imageBytes));
                    } catch (WriterException | IOException e) {
                        log.error("生成二维码失败", e);
                    }
                    return index;
                })
        );
    }

    /**
     * 导出excel文件
     */
//    @RequiresRoles("sa")
    @ApiOperation(value = "导出申请考试列表")
    @ResponseBody
    @RequestMapping(value = "/exportApplyExamList", method = {RequestMethod.POST})
    public void exportFile(HttpServletResponse response, @RequestBody SysExamApply reqDTO) {
        // 导出文件名
        String fileName = "导出的申请记录-" + System.currentTimeMillis() + ".xlsx";
        try {
            List<SysExamApply> list = paperService.applyExamList(reqDTO);
            List<SysExamApplyExportDTO> re = list.stream().map(index -> {
                SysExamApplyExportDTO temp = new SysExamApplyExportDTO();
                BeanMapper.copy(index, temp);
                BeanUtils.copyProperties(index, temp);
                if (StringUtils.isNumeric(index.getDeptId())) {
                    Optional.ofNullable(sysDepartService.getById(index.getDeptId()))
                            .ifPresent(depart -> temp.setDeptId(depart.getDeptName()));
                }
                ExamApply examApply = examApplyService.getBaseMapper().selectById(index.getId());
                StringBuilder sb = new StringBuilder();
                if (Objects.nonNull(examApply.getLicenses())) {
                    List<ApplyLicense> licenses = JSON.parseArray(JSON.toJSONString(examApply.getLicenses()), ApplyLicense.class);
                    licenses.stream().map(item -> {
                                log.info("证书信息：{}", item);
                                return JSON.parseObject(JSON.toJSONString(item), ApplyLicense.class);
                            })
                            .forEach(item -> sb.append("【证书名称】：").append(padRight(item.getName(), 15)).append(" ")
                                    .append("【资质类型】：").append(padRight(item.getType(), 15)).append(" ")
                                    .append("【准操项目】：").append(padRight(item.getProject(), 15)).append(" ")
                                    .append("【证书编号】：").append(padRight(item.getNumber(), 15)).append(" ")
                                    .append("【签发日期】：").append(padRight(item.getIssueDate(), 15)).append(" ")
                                    .append("【到期日期】：").append(padRight(item.getExpireDate(), 15)).append("\n"));
                    temp.setLicenses(sb.toString());
                }
                return temp;
            }).collect(Collectors.toList());
            new ExportExcel(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")) + " 导出申请记录",
                    SysExamApplyExportDTO.class)
                    .setImageRoot(imageRoot)
                    .setDataList(re)
                    .write(response, fileName)
                    .dispose();
        } catch (Exception e) {
            log.error("导出申请记录失败！失败信息：{}", e.getMessage(), e);
        }
    }

    public static String padRight(String str, int length) {
        if (str == null) str = "";
        int padLength = length - str.length();
        StringBuilder sb = new StringBuilder(str);
        for (int i = 0; i < padLength; i++) {
            sb.append(" ");
        }
        return sb.toString();
    }


    @ApiOperation(value = "匿名查询该用户最新的处于有效期的申请记录")
    @GetMapping("/getApplyExamAnon")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userName", value = "用户名", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "isApply", value = "isApply标识", dataType = "String", paramType = "query")
    })
    public ApiRest<ExamApply> getApplyExamAnon(String userName, String isApply) {
        Date now = new Date();
        ExamApply applyExam = examApplyService.getBaseMapper().selectOne(new QueryWrapper<ExamApply>()
                .lambda()
                .eq(StringUtils.isNotEmpty(userName), ExamApply::getUserName, userName)
                .eq(StringUtils.isNotEmpty(isApply), ExamApply::getIsApply, isApply)
                .ge(ExamApply::getLeaveTime, now)
                .le(ExamApply::getEntryTime, now)
                .orderByDesc(ExamApply::getCreateTime)
                .last(" LIMIT 1 ")
        );
        if (Objects.nonNull(applyExam)) {
            if (StringUtils.isNumeric(applyExam.getDeptId())) {
                Optional.ofNullable(sysDepartService.getById(applyExam.getDeptId()))
                        .ifPresent(depart -> applyExam.setWorkAreaName(depart.getDeptName()));
            }
            return super.success(applyExam);
        } else {
            return super.failure("无对应申请记录");
        }
    }

    @ApiOperation(value = "导出申请考试二维码压缩包")
    @ResponseBody
    @RequestMapping(value = "/exportApplyExamQRZIP", method = {RequestMethod.POST})
    public void exportApplyExamQRZIP(HttpServletResponse response, @RequestBody SysExamApply reqDTO) throws IOException {
        final List<SysExamApply> list = paperService.applyExamList(reqDTO);
        // 生成 ZIP 字节流
        ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();
        try (ZipOutputStream zos = new ZipOutputStream(zipOutputStream)) {
            list.forEach(index_ -> {
                try {
                    final String content = qrRoot + "/#/qr-code/" + URLEncoder.encode(index_.getUserName(), "UTF-8");
                    byte[] qrCodeBytes;
                    final String entryName = index_.getUserName() + "_" + sdf.format(index_.getEntryTime()) + "_" + sdf.format(index_.getLeaveTime()) + "_" + index_.getId() + ".png";
                    ZipEntry zipEntry = new ZipEntry(entryName);
                    zos.putNextEntry(zipEntry);
                    // 1. 生成二维码图像
                    BufferedImage qrImage = generateQRCodeImage(content, width, height);
                    // 2. 添加文本到二维码下方
                    BufferedImage finalImage = addTextBelowQRCode(qrImage, index_.getCompanyName() + " " + index_.getRealName());
                    // 3. 将图像转换为 byte[]
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write(finalImage, "PNG", baos); // 支持 PNG、JPEG 等格式
                    qrCodeBytes = baos.toByteArray();
                    zos.write(qrCodeBytes);
                    zos.closeEntry();
                } catch (Exception e) {
                    log.error("生成二维码失败！失败信息：{}", e.getMessage(), e);
                    throw new RuntimeException(e);
                }
            });
        }
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            // 设置响应头
            response.setContentType("application/zip");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + System.currentTimeMillis() + ".zip");
            // 输出 ZIP 流
            outputStream.write(zipOutputStream.toByteArray());
            outputStream.flush();
        }
    }

    /**
     * 生成二维码字节流
     *
     * @param content 二维码内容
     * @param width   宽
     * @param height  高
     * @return 压缩包路径
     * @throws Exception Exception
     */
    private static byte[] generateQRCodeBytes(String content, int width, int height) throws Exception {
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter()
                .encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream);
        return pngOutputStream.toByteArray();
    }

    /**
     * 生成二维码图片
     *
     * @param content 二维码内容
     * @param width   宽
     * @param height  高
     * @return BufferedImage
     * @throws WriterException WriterException
     */
    private static BufferedImage generateQRCodeImage(String content, int width, int height) throws WriterException {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        return MatrixToImageWriter.toBufferedImage(bitMatrix);
    }

    /**
     * 在二维码下方添加文本
     *
     * @param qrImage 二维码图像
     * @param text    文本
     * @return 新的图像
     */
    public static BufferedImage addTextBelowQRCode(BufferedImage qrImage, String text) {
        int width = qrImage.getWidth();
        int qrHeight = qrImage.getHeight();
        int textHeight = 30; // 额外空间用于文本
        int finalHeight = qrHeight + textHeight;
        // 创建新图像，包含二维码和文本区域
        BufferedImage combined = new BufferedImage(width, finalHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = combined.createGraphics();
        // 设置抗锯齿
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // 绘制二维码图像
        g2d.drawImage(qrImage, 0, 0, null);
        // 设置字体样式
        Font font = new Font("宋体", Font.BOLD, 30);
        g2d.setFont(font);
        g2d.setColor(Color.RED);
        // 计算文本居中位置
        FontMetrics fm = g2d.getFontMetrics();
        int textWidth = fm.stringWidth(text);
        int x = (width - textWidth) / 2;
        int y = qrHeight + fm.getAscent(); // 文本基线位置
        // 绘制文本
        g2d.drawString(text, x, y);
        g2d.dispose();
        return combined;
    }

    /**
     * 更新对应的申请状态
     *
     * @param reqDTO 请求参数
     * @return 更新结果
     */
    @ApiOperation(value = "更新对应的申请的状态")
    @RequestMapping(value = "updateApplyStatus", method = {RequestMethod.POST})
    public ApiRest<SysExamApply> updateApplyStatus(@RequestBody SysExamApplyUpdateStatusDTO reqDTO) {
        final String isApply = reqDTO.getIsApply();
        if (StringUtils.isNotEmpty(reqDTO.getIsApply())) {
            reqDTO.setIsApply(null);
        }
        List<SysExamApply> list = paperService.applyExamList(reqDTO);
        if (!reqDTO.getPhones().isEmpty()) {
            list = list
                    .stream()
                    .filter(index -> reqDTO.getPhones().contains(index.getPhone()))
                    .collect(Collectors.toList());
        }
        if (!reqDTO.getIds().isEmpty()) {
            list = list
                    .stream()
                    .filter(index -> reqDTO.getIds().contains(index.getId()))
                    .collect(Collectors.toList());
        }
        UpdateWrapper<ExamApply> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda()
                .in(ExamApply::getId, list.stream().map(SysExamApply::getId).collect(Collectors.toList()))
                .set(StringUtils.isNumeric(isApply), ExamApply::getIsApply, isApply)
        ;
        examApplyService.getBaseMapper().update(null, updateWrapper);
        return super.success("更新成功", null);
    }

    // 导出每个人的试卷得分情况与答题答案
    @ResponseBody
    @ApiOperation(value = "导出每个人的试卷得分情况与答题答案zip包")
    @RequestMapping(value = "/exportExamResultZIP", method = {RequestMethod.POST})
    public void exportExamResultZIP(HttpServletResponse response, @RequestBody SysExamApply reqDTO) throws IOException {
        final List<SysExamApply> list = paperService.applyExamList(reqDTO);
        // 生成 ZIP 字节流
        ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();
        try (ZipOutputStream zos = new ZipOutputStream(zipOutputStream)) {
            list.forEach(index_ -> {
                try {
                    final String entryName = index_.getRealName() + "_" + sdf.format(index_.getEntryTime()) + "_" + sdf.format(index_.getLeaveTime()) + "_" + index_.getId() + ".pdf";
                    ZipEntry zipEntry = new ZipEntry(entryName);
                    zos.putNextEntry(zipEntry);

                    SysUser sysUser = sysUserService.getBaseMapper().selectOne(new QueryWrapper<SysUser>()
                            .lambda()
                            .eq(SysUser::getUserName, index_.getUserName())
                            .last(" LIMIT 1 ")
                    );
                    Map<String, Object> data = new HashMap<>();
                    data.put("title", index_.getRealName() + "考试情况");
                    if (Objects.isNull(sysUser)) {
                        data.put("content", "未查询到该用户的考试结果");
                    } else {
                        final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        log.info("{} 对应id {} 申请id:{}", index_.getRealName(), sysUser.getId(), index_.getId());
                        List<UserExam> userExamList = userExamService.getBaseMapper().selectList(new QueryWrapper<UserExam>()
                                .lambda()
                                .eq(UserExam::getUserId, sysUser.getId())
                                .eq(UserExam::getApplyId, index_.getId())
                                .in(UserExam::getExamId, examOrderId)
                        ); // 列出该用户本次申请的考试结果记录
                        List<Map<String, Object>> papers = userExamList.stream().map(index -> new HashMap<String, Object>() {{
                            ExamDTO examDTO = examService.findById(index.getExamId());
                            put("examName", examDTO.getTitle());
                            put("examTime", formatter.format(index.getCreateTime()));
                            put("score", index.getMaxScore());
                            put("pass", index.getPassed() ? "通过" : "未通过");
                        }}).collect(Collectors.toList());
                        data.put("content", "以下为该用户本次入场申请考试概略情况");
                        log.info("{}对应考试结果{}", index_.getRealName(), papers);
                        data.put("papers", papers);
                        List<Map<String, Object>> exams = userExamList.stream().map(index -> new HashMap<String, Object>() {{
                            List<PaperQu> paperQuList = paperQuService.getBaseMapper().selectList(new QueryWrapper<PaperQu>()
                                    .lambda()
                                    .eq(PaperQu::getPaperId, index.getPaperId())
                                    .orderByAsc(PaperQu::getSort)
                            ); // 列出该份考卷所有问题
                            ObjectMapper objectMapper = new ObjectMapper();
                            List<Map<String, Object>> paperQu = paperQuList.parallelStream().map(qu -> {
                                Map<String, Object> map = objectMapper.convertValue(qu, Map.class);
                                QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
                                wrapper.lambda().eq(QuAnswer::getQuId, qu.getQuId());
                                List<QuAnswer> quAnswerList = quAnswerService.list(wrapper); // 列出该问题所有答案
                                Qu quInfo = quService.getById(qu.getQuId());
                                map.put("quAnswerList", quAnswerList.stream().map(answer -> objectMapper.convertValue(answer, Map.class)).collect(Collectors.toList()));
                                map.put("quInfo", quInfo);
                                List<PaperQuAnswer> paperQuAnswerList = paperQuAnswerService.getBaseMapper().selectList(new QueryWrapper<PaperQuAnswer>()
                                        .lambda()
                                        .eq(PaperQuAnswer::getPaperId, index.getPaperId())
                                        .eq(PaperQuAnswer::getQuId, qu.getQuId())
                                        .eq(PaperQuAnswer::getChecked, Boolean.TRUE)
                                        .orderByAsc(PaperQuAnswer::getSort)
                                ); // 列出该问题的答案
                                map.put("paperQuAnswerList", paperQuAnswerList.stream().map(answer -> objectMapper.convertValue(answer, Map.class)).collect(Collectors.toList()));
                                return map;
                            }).collect(Collectors.toList());
                            log.info("{}列出该份考卷所有问题{}", index.getPaperId(), paperQuList);
                            put("paperQu", paperQu); // 列出该份考卷所有问题与该用户答案
                            ExamDTO examDTO = examService.findById(index.getExamId());
                            put("pageTitle", examDTO.getTitle());
                            put("examTime", formatter.format(index.getCreateTime()));
                            put("score", index.getMaxScore());
                            put("pass", index.getPassed() ? "通过" : "未通过");
                        }}).collect(Collectors.toList());
                        data.put("exams", exams);
                    }
                    byte[] pdf = pdfFileUtil.generatePdf("export", data);
                    log.info(JSON.toJSONString(data));
                    zos.write(pdf);
                    zos.closeEntry();
                } catch (Exception e) {
                    log.error("生成对应pdf文件失败！失败信息：{}", e.getMessage(), e);
                    throw new RuntimeException(e);
                }
            });
        }
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            // 设置响应头
            response.setContentType("application/zip");
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + System.currentTimeMillis() + ".zip");
            // 输出 ZIP 流
            outputStream.write(zipOutputStream.toByteArray());
            outputStream.flush();
        }
    }

}
